home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_10_08
/
qc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-07
|
12KB
|
449 lines
///////////////////////////////////////////////////////
// Listing 2 - QC.CPP: Quadcode support routines
// Written by:
// Kenneth Van Camp
// RR #1 Box 1255
// East Stroudsburg, PA 18301
// (717)223-8620
//
// Functions -
// QuadCode::FreeMem free memory from qc
// QuadCode::QuadCode constructor from (I,J)
// QuadCode::Init initializer from string
// QuadCode::GetQuit get val of single quit
// QuadCode::SetQuit set val of single quit
// QuadCode::ToIJ convert to (I,J) coords
// QuadCode::Compare compare two quadcodes
// QuadCode::Sibling are two qc's siblings?
// QuadCode::Contains does qc contain it?
// QuadCode::MakeParent make qc into its parent
// QuadCode::operator= assignment operator
// operator<< qc "put to" stream
// operator>> qc "get from" stream
//
///////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef __TURBOC__
#include <iostream.h>
#else
#include <stream.hpp>
#endif
#include "qc.h"
// The following macro returns the number of bytes reqd
// to store a quadcode, given the number of quits:
#define QC_NBYTES(q) (((q) - 1) / 4 + 1)
// These are shifts & masks to extract a single quit
static int QCshifts[4] = { 6, 4, 2, 0 };
static int QCmasks[4] = { 3<<6, 3<<4, 3<<2, 3 };
// This is the inverse mask:
static int QCimasks[4] =
{ 0xff^(3<<6), 0xff^(3<<4), 0xff^(3<<2), 0xff^3 };
// And these are masks for each bit in a normal byte:
static int bitmasks[8] =
{ 1, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7 };
///////////////////////////////////////////////////////
// QuadCode::FreeMem: Free dynamic memory.
#ifndef STAT_QC
void QuadCode::FreeMem (void)
{
if (nquits > 0 && qca)
delete qca;
qca = NULL;
nquits = 0;
} // QuadCode::FreeMem
#endif // STAT_QC
///////////////////////////////////////////////////////
// QuadCode::QuadCode: QuadCode constructor from (I,J)
// coordinates of the upper-left corner of the qc.
QuadCode::QuadCode (COORD i, COORD j, int nq)
// i is the vertical row# of quadcode (0 at top)
// j is the horizontal column# of quadcode
// nq is the # of quits in quadcode
{
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);
// We traverse both the (i,j) coordinates and the qc
// from the msb to the lsb and msq to msq. Note the
// following assumes MAXQUITS is a multiple of 8.
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + (MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + (MAXQUITS - nq) / 8;
#else
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
#endif
int bit = 7 - (MAXQUITS - nq) % 8;
int nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif
memset (qca, '\0', nbytes);
BYTE *p = qca;
nquits = nq;
int pos = 0; // position within qc (0,1,2,3)
for ( ; nq > 0; nq--)
{
if (*ip & bitmasks[bit])
*p |= 1 << (QCshifts[pos] + 1);
if (*jp & bitmasks[bit])
*p |= 1 << QCshifts[pos];
// Advance to next quit
if (++pos > 3)
{
pos = 0;
p++;
}
// Back up to next bit
if (--bit < 0)
{
bit = 7;
#ifdef MSB_FIRST
ip++;
jp++;
#else
ip--;
jp--;
#endif
} // if --bit
} // for nq
} // QuadCode::QuadCode
///////////////////////////////////////////////////////
// QuadCode::Init: QuadCode initializer from string.
void QuadCode::Init (const char *chqc)
// chqc is the quadcode in a null-terminated
// character representation - i.e., "123"
{
int nq = strlen (chqc);
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);
size_t nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif
memset (qca, '\0', nbytes);
// Store quadcode in binary form, from msq to lsq.
int i;
int pos; // pos within byte of this quit (0,1,2,3)
BYTE *p; // ptr to current byte in qc
for (i = 0, pos = 0, p = qca; i < nq; i++)
{
int val = chqc[i] - '0';
assert (val >= 0 && val <= 3);
*p |= val << QCshifts[pos];
if (++pos > 3)
{
pos = 0;
p++;
}
} // for i
nquits = nq;
} // QuadCode::Init
///////////////////////////////////////////////////////
// QuadCode::GetQuit: Return single quit from quadcode.
int QuadCode::GetQuit (int quit)
// quit is the pos# of the quit to extract (zero-based).
// Pos 0 is the high-order quit ('1' in "123").
{
assert (quit <= nquits && quit >= 0);
int byte = quit / 4;
int pos = quit % 4;
return ( (*(qca + byte) & QCmasks[pos]) >>
QCshifts[pos]);
} // QuadCode::GetQuit
///////////////////////////////////////////////////////
// QuadCode::SetQuit: Set value of a single quit.
void QuadCode::SetQuit (int quit, int val)
// quit is the pos# of the quit to extract (zero-based).
// val is the value of the quit (0, 1, 2 or 3).
{
assert (quit <= nquits && quit >= 0 && val >= 0 &&
val < 4);
BYTE *p = qca + quit / 4;
int pos = quit % 4;
// Clear out the old value
*p &= (255 - QCmasks[pos]);
// Put in the new value
*p |= val << QCshifts[pos];
} // QuadCode::SetQuit
///////////////////////////////////////////////////////
// QuadCode::ToIJ: Convert the quadcode value to (I,J).
// The offsets returned are the coords of the
// upper-left corner of the quadcode.
void QuadCode::ToIJ (COORD &i, COORD &j, int &nq)
// i is the row#
// j is the col#
// nq is the #quits
{
i = j = nq = 0;
if (nquits < 1)
return;
assert (nquits <= MAXQUITS);
nq = nquits;
// Go from lsq to msq. Following loop is based on the
// conversion algorithm by Gargantini:
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1;
#else
BYTE *ip = (BYTE *)&i;
BYTE *jp = (BYTE *)&j;
#endif
int quit, // current quit# in qc
bit = 0; // current bit# in byte of (i,j)
for (quit = nquits-1; quit >= 0; quit--)
{
int val = GetQuit (quit);
// Bit pos 0 gives J val, bit pos 1 gives I val.
int ival = val >> 1;
int jval = val & 1;
*ip |= (ival << bit);
*jp |= (jval << bit);
// Advance to next bit
if (bit == 7)
{
bit = 0;
#ifdef MSB_FIRST
ip--;
jp--;
#else
ip++;
jp++;
#endif
}
else
bit++;
} // for quit
} // QuadCode::ToIJ
///////////////////////////////////////////////////////
// QuadCode::Compare: Compare one quadcode to another.
// Return 0 if the two quadcodes are equal; -1 if the
// current quadcode is less than qc; or +1 if the
// current quadcode is greater than qc.
int QuadCode::Compare (QuadCode &qc)
// qc is the quadcode to compare to
{
// Check for zero-length quadcodes
if (nquits == 0)
{
if (qc.nquits == 0)
return 0;
else
return -1;
}
else if (qc.nquits == 0)
return 1;
BYTE *p1 = qca;
BYTE *p2 = qc.qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;
// Compare each byte of the two quadcodes.
for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
if (*p1 != *p2)
{
if (*p1 < *p2)
return -1;
else
return 1;
}
if (nquits == qc.nquits)
// quadcodes same
return 0;
else if (nquits < qc.nquits)
// this quadcode contains qc
return -1;
else
// qc contains this quadcode
return 1;
} // QuadCode::Compare
///////////////////////////////////////////////////////
// QuadCode::Sibling: Compare one quadcode to another.
// Return TRUE if they are siblings, FALSE if not.
int QuadCode::